package org.linlinjava.litemall.wx.web;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.linlinjava.litemall.core.notify.NotifyService;
import org.linlinjava.litemall.core.notify.NotifyType;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.db.domain.LitemallAwardPlan;
import org.linlinjava.litemall.db.domain.LitemallUser;
import org.linlinjava.litemall.db.domain.LitemallUserLottery;
import org.linlinjava.litemall.db.service.LitemallUserService;
import org.linlinjava.litemall.wx.annotation.LoginUser;
import org.linlinjava.litemall.wx.service.LotteryService;
import org.linlinjava.litemall.wx.util.GetTomorrowSecond;
import org.linlinjava.litemall.wx.util.TimeJudge;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.Jedis;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 抽奖活动
 *
 * @author zhy
 * @date 2019-07-03 10:57
 **/
@RestController
@RequestMapping("/wx/lottery")
public class WxLotteryController {
	private final Log logger = LogFactory.getLog(WxLotteryController.class);
    @Resource
    private NotifyService notifyService;

	@Resource
	private LotteryService lotteryService;

	@Resource
	private StringRedisTemplate stringRedisTemplate;

	@Resource
	private LitemallUserService userService;

	@Resource
	private GetTomorrowSecond getTomorrowSecond;

	@Resource
	private TimeJudge timeJudge;

	private static final String KEY = "hasAwardFlag";

	private static final String KEY2 = "canLotteryflag";

	private int maxLotteryNum = 3;

	private final ReadWriteLock lock = new ReentrantReadWriteLock();

	private final Lock writeLock = lock.writeLock();

	private int[] arr = {3, 5, 7};

	/**
	 * 存最近一段时间中奖者数据
	 */
	private static List<LitemallUserLottery> list = new ArrayList();

	@GetMapping("/award")
	public Object getAward(@LoginUser Integer userId) {
		if (userId == null) {
			return ResponseUtil.unlogin();
		}
		// 判断用户今天是否还有抽奖机会
		try (Jedis jedis = new Jedis("localhost", 6379)) {
			long c = jedis.incr(userId+"lottery");
			if (c > maxLotteryNum) {
				return ResponseUtil.fail(-1, "今日抽奖次数已用完");
			}else{
				if(c==1){
					//设置过期时间
					jedis.expire(userId+"lottery",getTomorrowSecond.getSecond());
				}
			}
		}
		Integer lotteryId;
		int num = (int)lotteryService.getUserLotteryNum(userId);
		if (num < maxLotteryNum) {
			// 扣减用户积分
			if (lotteryService.reduce(userId) != 1) {
				try (Jedis jedis = new Jedis("localhost", 6379)) {
					jedis.decr(userId+"lottery");
				}
				return ResponseUtil.fail(-2, "积分不足");
			}
			// 添加用户抽奖记录
			lotteryId = lotteryService.insertRecord(userId);
			// 钱包记录
			lotteryService.insertWallet(userId);
		} else {
			return ResponseUtil.fail(-1, "今日抽奖次数已用完");
		}

		// 计算用户能否抽到奖
		LitemallAwardPlan litemallAwardPlan = doLottery(userId, lotteryId);
		if (litemallAwardPlan == null) {
			return ResponseUtil.ok(arr[(int)(Math.random() * arr.length)]);
		} else {
			return ResponseUtil.ok(litemallAwardPlan.getAwardId());
		}
	}

	private LitemallAwardPlan doLottery(Integer userId, Integer lotteryId) {
		Thread thread = Thread.currentThread();
		LitemallAwardPlan litemallAwardPlanx = null;
		// 判断现在奖池有没有奖.如果取出来有值代表奖池有奖
		String objectMap = stringRedisTemplate.opsForValue().get(KEY);
		System.out.println("我是第" + thread.getId() + "线程发起抽奖,奖池大小：" + objectMap);
		if (StringUtils.isEmpty(objectMap)) {
			return null;
		} else {
			Random random = new Random();
			int r = random.nextInt(25);
			System.out.println(userId + "我是第" + thread.getId() + ",r=" + r);
			// 恭喜你，你有权去抽奖池抽奖了
			if (r == 1) {
				writeLock.lock();
				try {
					Random random1 = new Random();
					// 我看看最近半小时内有没有人中过奖
					String value = stringRedisTemplate.opsForValue().get(KEY2);
					if (StringUtils.isEmpty(value)) {
						//看他15天内有没有抽中过奖
						LitemallUserLottery litemallUserLottery = lotteryService.confirmHasAward(userId);
						if (litemallUserLottery != null) {
							return null;
						} else {
							//抽奖
							// 1.从数据库抽取一份今日的奖品列表
							LitemallAwardPlan litemallAwardPlan = lotteryService.getOnePlan();
							if (litemallAwardPlan != null) {
								// 2.尝试将奖品数量减1，如果成功，则代表奖品抽取成功
								if (lotteryService.reduceNum(litemallAwardPlan.getId()) != 1) {
								} else {
									// 30+左右的时间内不产生新的中奖用户
									stringRedisTemplate.opsForValue().set(KEY2, KEY2, random1.nextInt(10) + 20, TimeUnit.MINUTES);
									// 数据库增加中奖信息
									LitemallUserLottery litemallUserLottery1 = new LitemallUserLottery();
									LitemallUser litemallUser = userService.findById(userId);
									litemallUserLottery1.setId(lotteryId);
									litemallUserLottery1.setAwardId(litemallAwardPlan.getAwardId());
									litemallUserLottery1.setAwardName(litemallAwardPlan.getAwardName());
									litemallUserLottery1.setUserName(litemallUser.getUsername());
									litemallUserLottery1.setCreateTime(LocalDateTime.now());
									litemallUserLottery1.setSendFlag((short)1);
									litemallUserLottery1.setIntegral(litemallAwardPlan.getIntegral());
									lotteryService.updateLotteryRecord(litemallUserLottery1);
									// 发送模板消息
									Date dd=new Date();
									SimpleDateFormat sim=new SimpleDateFormat("yyyy-MM-dd");
									String time=sim.format(dd);
									String[] params = new String[] {litemallAwardPlan.getAwardName(), time, "恭喜您中奖，请在小程序中设置您的默认收货地址，以便发货。"};
									notifyService.notifyWxTemplate(litemallUser.getWeixinOpenid(), NotifyType.LOTTERYSUCCESS, params);
									litemallAwardPlanx = litemallAwardPlan;
								}
							} else {
								// redis设置奖池为空的标志
								stringRedisTemplate.delete(KEY);
							}
						}
					} else {
					}
				}
				finally {
					writeLock.unlock();
				}
			} else {
			}
		}
		return litemallAwardPlanx;
	}

	/**
	 * 凌晨0:1:0
	 */
	@Scheduled(cron = "0 1 0 1 * ? ")
	@Async
	public void getLotteryPlan() {
		//更新用户的抽奖次数
		logger.info("更新用户的抽奖次数");
		maxLotteryNum = lotteryService.getNum().getNum();
		List<LitemallAwardPlan> awardPlanList = lotteryService.getAwardPlan();
		if (awardPlanList.size() == 0) {
			stringRedisTemplate.delete(KEY);
		}
	}

	private void setFlag() {
		LocalTime midnight = LocalTime.MIDNIGHT;
		LocalDate today = LocalDate.now();
		LocalDateTime todayMidnight = LocalDateTime.of(today, midnight);
		LocalDateTime tomorrowMidnight = todayMidnight.plusDays(1);
		int expireTime = (int)TimeUnit.NANOSECONDS.toHours(Duration.between(LocalDateTime.now(), tomorrowMidnight).toNanos());
		stringRedisTemplate.opsForValue().set(KEY, "0", expireTime, TimeUnit.HOURS);
	}

	/**
	 * 半小时查询一次奖池有没有奖
	 */
	@Scheduled(cron = "0 0/30 * * * ? ")
	@Async
	public void searchAward() {
		logger.info("查询一次奖池有没有奖");
		//判断时间
		boolean flag=false;
		try {
			flag = timeJudge.isTimeRange();
		}
		catch (ParseException e) {
			e.printStackTrace();
		}
		if(flag){
			LitemallAwardPlan litemallAwardPlan = lotteryService.getOnePlan();
			if (litemallAwardPlan != null) {
				setFlag();
			}else {
				stringRedisTemplate.delete(KEY);
			}
		}
	}

	/**
	 * 加载奖池
	 *
	 * @return
	 */
	@GetMapping("/getLottery")
	public Object getLottery(@LoginUser Integer userId) {
		if (userId == null) {
			return ResponseUtil.unlogin();
		}

		Map<String, Object> map = new HashMap<>(3);
		map.put("items", lotteryService.getAwardList());
		map.put("num", maxLotteryNum - (int)lotteryService.getUserLotteryNum(userId));
		// 中奖用户信息
		map.put("lotteryUser", list);
		return ResponseUtil.ok(map);
	}


	/**
	 * 获取中奖用户，在小程序端轮番播放
	 * 2小时执行一次
	 */
	@Scheduled(cron = "0 0 0/2 * * ?")
	@Async
	@PostConstruct
	public void getLotterUser() {
		logger.info("获取中奖用户，在小程序端轮番播放");
		List<LitemallUserLottery> list1 = lotteryService.getAwardUser();
		list.clear();
		if (list1.size() > 5) {
			int i = 0;
			for (LitemallUserLottery litemallUserLottery : list1) {
				i++;
				if (i < 5) {
					LitemallUserLottery litemallUserLottery1 = new LitemallUserLottery();
					litemallUserLottery1.setAwardName("用户：" + litemallUserLottery.getUserName().substring(0, 1) + "** 抽中了" + litemallUserLottery.getAwardName());
					list.add(litemallUserLottery1);
				}
			}
		} else if (list1.size() == 0) {
		} else {
			for (LitemallUserLottery litemallUserLottery : list1) {
				LitemallUserLottery litemallUserLottery1 = new LitemallUserLottery();
				litemallUserLottery1.setAwardName("用户：" + litemallUserLottery.getUserName().substring(0, 1) + "** 抽中了" + litemallUserLottery.getAwardName());
				list.add(litemallUserLottery1);
			}
		}
	}

}
